
package net.lab0.nebula.gui;


import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Date;

import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.lab0.nebula.core.QuadTreeManager;
import net.lab0.nebula.gui.enums.PowerOfTwoInteger;
import net.lab0.nebula.listener.QuadTreeManagerListener;

import com.toedter.calendar.JDateChooser;


@SuppressWarnings("serial")
public class ComputationPanel
extends JPanel
{
    private final ButtonGroup            buttonGroup = new ButtonGroup();
    private JDateChooser                 dateChooser;
    private JComboBox<PowerOfTwoInteger> cmbxNodesPerPass;
    private JComboBox<PowerOfTwoInteger> cmbxPasses;
    private JRadioButton                 rdbtnFullComputation;
    private JSpinner                     spnrThreads;
    private JCheckBox                    chckbxUpdateStatisticsAfter;
    private JSpinner                     spnrSaveEveryXPass;
    
    private MainWindow                   mainWindow;
    private JProgressBar                 progressBarNodesForThisPass;
    private JLabel                       lblFinishStatusValue;
    private JProgressBar                 progressBarPasses;
    
    private Thread                       computationThread;
    private JCheckBox                    chckbxSaveEvery;
    private JTextField                   txtSuffixValue;
    private JCheckBox                    lblAddSuffix;
    private JTextField                   txtSavePath;
    private File                         saveFile;
    private JCheckBox                    chckbxOverwriteOriginalFile;
    private JButton                      btnBrowse;
    private JButton                      btnStart;
    private JButton                      btnStop;
    
    private boolean                      keepComputing;
    private JRadioButton                 rdbtnPasses;
    private JRadioButton                 rdbtnDate;
    
    // useful for window builder
    @SuppressWarnings("unused")
    private ComputationPanel()
    {
        this(null);
    }
    
    public ComputationPanel(MainWindow mainWindow)
    {
        this.mainWindow = mainWindow;
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        
        JPanel panel_7 = new JPanel();
        panel_7.setBorder(new TitledBorder(null, "Stop criterion", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        this.add(panel_7);
        GridBagLayout gbl_panel_7 = new GridBagLayout();
        gbl_panel_7.columnWidths = new int[] { 0, 0, 0 };
        gbl_panel_7.rowHeights = new int[] { 0, 0, 0, 0 };
        gbl_panel_7.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
        gbl_panel_7.rowWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE };
        panel_7.setLayout(gbl_panel_7);
        
        rdbtnDate = new JRadioButton("Date");
        rdbtnDate.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                dateChooser.setEnabled(rdbtnDate.isSelected());
            }
        });
        buttonGroup.add(rdbtnDate);
        GridBagConstraints gbc_rdbtnDate = new GridBagConstraints();
        gbc_rdbtnDate.anchor = GridBagConstraints.WEST;
        gbc_rdbtnDate.insets = new Insets(0, 0, 5, 5);
        gbc_rdbtnDate.gridx = 0;
        gbc_rdbtnDate.gridy = 0;
        panel_7.add(rdbtnDate, gbc_rdbtnDate);
        
        dateChooser = new JDateChooser("yyyy-MM-dd HH:mm:ss", "####-##-## ##:##:##", '_');
        dateChooser.setMinSelectableDate(new Date());
        dateChooser.setEnabled(false);
        GridBagConstraints gbc_dateChooser = new GridBagConstraints();
        gbc_dateChooser.insets = new Insets(0, 0, 5, 0);
        gbc_dateChooser.fill = GridBagConstraints.BOTH;
        gbc_dateChooser.gridx = 1;
        gbc_dateChooser.gridy = 0;
        panel_7.add(dateChooser, gbc_dateChooser);
        
        rdbtnPasses = new JRadioButton("Passes");
        rdbtnPasses.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                cmbxPasses.setEnabled(rdbtnPasses.isSelected());
            }
        });
        buttonGroup.add(rdbtnPasses);
        GridBagConstraints gbc_rdbtnPasses = new GridBagConstraints();
        gbc_rdbtnPasses.insets = new Insets(0, 0, 5, 5);
        gbc_rdbtnPasses.anchor = GridBagConstraints.WEST;
        gbc_rdbtnPasses.gridx = 0;
        gbc_rdbtnPasses.gridy = 1;
        panel_7.add(rdbtnPasses, gbc_rdbtnPasses);
        
        cmbxPasses = new JComboBox<>();
        cmbxPasses.setEnabled(false);
        cmbxPasses.setModel(new DefaultComboBoxModel<PowerOfTwoInteger>(PowerOfTwoInteger.values()));
        GridBagConstraints gbc_cmbxPasses = new GridBagConstraints();
        gbc_cmbxPasses.insets = new Insets(0, 0, 5, 0);
        gbc_cmbxPasses.fill = GridBagConstraints.HORIZONTAL;
        gbc_cmbxPasses.gridx = 1;
        gbc_cmbxPasses.gridy = 1;
        panel_7.add(cmbxPasses, gbc_cmbxPasses);
        
        rdbtnFullComputation = new JRadioButton("Full computation");
        rdbtnFullComputation.setSelected(true);
        buttonGroup.add(rdbtnFullComputation);
        GridBagConstraints gbc_rdbtnFullComputation = new GridBagConstraints();
        gbc_rdbtnFullComputation.anchor = GridBagConstraints.WEST;
        gbc_rdbtnFullComputation.insets = new Insets(0, 0, 0, 5);
        gbc_rdbtnFullComputation.gridx = 0;
        gbc_rdbtnFullComputation.gridy = 2;
        panel_7.add(rdbtnFullComputation, gbc_rdbtnFullComputation);
        
        JPanel panel_4 = new JPanel();
        panel_4.setBorder(new TitledBorder(null, "Options", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        this.add(panel_4);
        GridBagLayout gbl_panel_4 = new GridBagLayout();
        gbl_panel_4.columnWidths = new int[] { 0, 0, 0, 0 };
        gbl_panel_4.rowHeights = new int[] { 0, 16, 0, 0, 0, 0, 0 };
        gbl_panel_4.columnWeights = new double[] { 0.0, 1.0, 0.0, Double.MIN_VALUE };
        gbl_panel_4.rowWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE };
        panel_4.setLayout(gbl_panel_4);
        
        JLabel lblNodesPerPass = new JLabel("Nodes per pass");
        GridBagConstraints gbc_lblNodesPerPass = new GridBagConstraints();
        gbc_lblNodesPerPass.anchor = GridBagConstraints.EAST;
        gbc_lblNodesPerPass.insets = new Insets(0, 0, 5, 5);
        gbc_lblNodesPerPass.gridx = 0;
        gbc_lblNodesPerPass.gridy = 0;
        panel_4.add(lblNodesPerPass, gbc_lblNodesPerPass);
        
        cmbxNodesPerPass = new JComboBox<>();
        GridBagConstraints gbc_cmbxNodesPerPass = new GridBagConstraints();
        gbc_cmbxNodesPerPass.fill = GridBagConstraints.HORIZONTAL;
        gbc_cmbxNodesPerPass.insets = new Insets(0, 0, 5, 5);
        gbc_cmbxNodesPerPass.gridx = 1;
        gbc_cmbxNodesPerPass.gridy = 0;
        panel_4.add(cmbxNodesPerPass, gbc_cmbxNodesPerPass);
        cmbxNodesPerPass.setModel(new DefaultComboBoxModel<PowerOfTwoInteger>(PowerOfTwoInteger.values()));
        cmbxNodesPerPass.getModel().setSelectedItem(PowerOfTwoInteger._1Ki);
        
        JLabel lblThreadsCount = new JLabel("Threads count");
        GridBagConstraints gbc_lblThreadsCount = new GridBagConstraints();
        gbc_lblThreadsCount.insets = new Insets(0, 0, 5, 5);
        gbc_lblThreadsCount.anchor = GridBagConstraints.EAST;
        gbc_lblThreadsCount.gridx = 0;
        gbc_lblThreadsCount.gridy = 1;
        panel_4.add(lblThreadsCount, gbc_lblThreadsCount);
        
        spnrThreads = new JSpinner();
        GridBagConstraints gbc_spnrThreads = new GridBagConstraints();
        gbc_spnrThreads.insets = new Insets(0, 0, 5, 5);
        gbc_spnrThreads.fill = GridBagConstraints.HORIZONTAL;
        gbc_spnrThreads.gridx = 1;
        gbc_spnrThreads.gridy = 1;
        panel_4.add(spnrThreads, gbc_spnrThreads);
        spnrThreads.setModel(new SpinnerNumberModel(Runtime.getRuntime().availableProcessors() / 2, 1, Runtime.getRuntime().availableProcessors(), 1));
        
        chckbxSaveEvery = new JCheckBox("Save every");
        chckbxSaveEvery.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                spnrSaveEveryXPass.setEnabled(chckbxSaveEvery.isSelected());
            }
        });
        GridBagConstraints gbc_chckbxSaveEvery = new GridBagConstraints();
        gbc_chckbxSaveEvery.anchor = GridBagConstraints.EAST;
        gbc_chckbxSaveEvery.insets = new Insets(0, 0, 5, 5);
        gbc_chckbxSaveEvery.gridx = 0;
        gbc_chckbxSaveEvery.gridy = 2;
        panel_4.add(chckbxSaveEvery, gbc_chckbxSaveEvery);
        
        spnrSaveEveryXPass = new JSpinner();
        spnrSaveEveryXPass.setEnabled(false);
        spnrSaveEveryXPass.setModel(new SpinnerNumberModel(1, 1, 10, 1));
        GridBagConstraints gbc_spnrSaveEveryXPass = new GridBagConstraints();
        gbc_spnrSaveEveryXPass.fill = GridBagConstraints.HORIZONTAL;
        gbc_spnrSaveEveryXPass.insets = new Insets(0, 0, 5, 5);
        gbc_spnrSaveEveryXPass.gridx = 1;
        gbc_spnrSaveEveryXPass.gridy = 2;
        panel_4.add(spnrSaveEveryXPass, gbc_spnrSaveEveryXPass);
        
        JLabel lblPass = new JLabel("pass");
        GridBagConstraints gbc_lblPass = new GridBagConstraints();
        gbc_lblPass.anchor = GridBagConstraints.WEST;
        gbc_lblPass.insets = new Insets(0, 0, 5, 0);
        gbc_lblPass.gridx = 2;
        gbc_lblPass.gridy = 2;
        panel_4.add(lblPass, gbc_lblPass);
        
        lblAddSuffix = new JCheckBox("Intermediate save suffix");
        lblAddSuffix.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                txtSuffixValue.setEnabled(lblAddSuffix.isSelected());
            }
        });
        GridBagConstraints gbc_lblAddSuffix = new GridBagConstraints();
        gbc_lblAddSuffix.anchor = GridBagConstraints.EAST;
        gbc_lblAddSuffix.insets = new Insets(0, 0, 5, 5);
        gbc_lblAddSuffix.gridx = 0;
        gbc_lblAddSuffix.gridy = 3;
        panel_4.add(lblAddSuffix, gbc_lblAddSuffix);
        
        txtSuffixValue = new JTextField();
        txtSuffixValue.setEnabled(false);
        GridBagConstraints gbc_txtSuffixValue = new GridBagConstraints();
        gbc_txtSuffixValue.insets = new Insets(0, 0, 5, 5);
        gbc_txtSuffixValue.fill = GridBagConstraints.HORIZONTAL;
        gbc_txtSuffixValue.gridx = 1;
        gbc_txtSuffixValue.gridy = 3;
        panel_4.add(txtSuffixValue, gbc_txtSuffixValue);
        txtSuffixValue.setColumns(10);
        
        chckbxUpdateStatisticsAfter = new JCheckBox("Update statistics after each pass");
        GridBagConstraints gbc_chckbxUpdateStatisticsAfter = new GridBagConstraints();
        gbc_chckbxUpdateStatisticsAfter.insets = new Insets(0, 0, 5, 5);
        gbc_chckbxUpdateStatisticsAfter.anchor = GridBagConstraints.WEST;
        gbc_chckbxUpdateStatisticsAfter.gridwidth = 2;
        gbc_chckbxUpdateStatisticsAfter.gridx = 0;
        gbc_chckbxUpdateStatisticsAfter.gridy = 4;
        panel_4.add(chckbxUpdateStatisticsAfter, gbc_chckbxUpdateStatisticsAfter);
        
        chckbxOverwriteOriginalFile = new JCheckBox("Overwrite original file");
        chckbxOverwriteOriginalFile.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                btnBrowse.setEnabled(!chckbxOverwriteOriginalFile.isSelected());
            }
        });
        GridBagConstraints gbc_chckbxOverwriteOriginalFile = new GridBagConstraints();
        gbc_chckbxOverwriteOriginalFile.anchor = GridBagConstraints.EAST;
        gbc_chckbxOverwriteOriginalFile.insets = new Insets(0, 0, 0, 5);
        gbc_chckbxOverwriteOriginalFile.gridx = 0;
        gbc_chckbxOverwriteOriginalFile.gridy = 5;
        panel_4.add(chckbxOverwriteOriginalFile, gbc_chckbxOverwriteOriginalFile);
        
        txtSavePath = new JTextField();
        txtSavePath.setEditable(false);
        GridBagConstraints gbc_txtSavePath = new GridBagConstraints();
        gbc_txtSavePath.insets = new Insets(0, 0, 0, 5);
        gbc_txtSavePath.fill = GridBagConstraints.HORIZONTAL;
        gbc_txtSavePath.gridx = 1;
        gbc_txtSavePath.gridy = 5;
        panel_4.add(txtSavePath, gbc_txtSavePath);
        txtSavePath.setColumns(10);
        
        btnBrowse = new JButton("Browse...");
        btnBrowse.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                chooseSaveFolder();
            }
        });
        GridBagConstraints gbc_btnBrowse = new GridBagConstraints();
        gbc_btnBrowse.gridx = 2;
        gbc_btnBrowse.gridy = 5;
        panel_4.add(btnBrowse, gbc_btnBrowse);
        
        JPanel panel_6 = new JPanel();
        this.add(panel_6);
        GridBagLayout gbl_panel_6 = new GridBagLayout();
        gbl_panel_6.columnWidths = new int[] { 0, 0, 0 };
        gbl_panel_6.rowHeights = new int[] { 0, 0 };
        gbl_panel_6.columnWeights = new double[] { 1.0, 1.0, Double.MIN_VALUE };
        gbl_panel_6.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
        panel_6.setLayout(gbl_panel_6);
        
        btnStart = new JButton("Start");
        btnStart.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                startComputation();
            }
        });
        GridBagConstraints gbc_btnStart = new GridBagConstraints();
        gbc_btnStart.anchor = GridBagConstraints.EAST;
        gbc_btnStart.insets = new Insets(0, 0, 0, 5);
        gbc_btnStart.gridx = 0;
        gbc_btnStart.gridy = 0;
        panel_6.add(btnStart, gbc_btnStart);
        
        btnStop = new JButton("Stop");
        btnStop.setEnabled(false);
        btnStop.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                stopComputation();
            }
        });
        GridBagConstraints gbc_btnStop = new GridBagConstraints();
        gbc_btnStop.anchor = GridBagConstraints.WEST;
        gbc_btnStop.gridx = 1;
        gbc_btnStop.gridy = 0;
        panel_6.add(btnStop, gbc_btnStop);
        
        JPanel panel = new JPanel();
        add(panel);
        GridBagLayout gbl_panel = new GridBagLayout();
        gbl_panel.columnWidths = new int[] { 34, 0, 0 };
        gbl_panel.rowHeights = new int[] { 16, 0, 0, 0 };
        gbl_panel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
        gbl_panel.rowWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE };
        panel.setLayout(gbl_panel);
        
        JLabel lblPasses = new JLabel("Passes");
        GridBagConstraints gbc_lblPasses = new GridBagConstraints();
        gbc_lblPasses.insets = new Insets(0, 0, 5, 5);
        gbc_lblPasses.anchor = GridBagConstraints.NORTHEAST;
        gbc_lblPasses.gridx = 0;
        gbc_lblPasses.gridy = 0;
        panel.add(lblPasses, gbc_lblPasses);
        
        progressBarPasses = new JProgressBar();
        progressBarPasses.setStringPainted(true);
        GridBagConstraints gbc_progressBar = new GridBagConstraints();
        gbc_progressBar.fill = GridBagConstraints.HORIZONTAL;
        gbc_progressBar.insets = new Insets(0, 0, 5, 0);
        gbc_progressBar.gridx = 1;
        gbc_progressBar.gridy = 0;
        panel.add(progressBarPasses, gbc_progressBar);
        
        JLabel lblNodesForThis = new JLabel("Nodes for this pass");
        GridBagConstraints gbc_lblNodesForThis = new GridBagConstraints();
        gbc_lblNodesForThis.insets = new Insets(0, 0, 5, 5);
        gbc_lblNodesForThis.anchor = GridBagConstraints.EAST;
        gbc_lblNodesForThis.gridx = 0;
        gbc_lblNodesForThis.gridy = 1;
        panel.add(lblNodesForThis, gbc_lblNodesForThis);
        
        progressBarNodesForThisPass = new JProgressBar();
        progressBarNodesForThisPass.setStringPainted(true);
        GridBagConstraints gbc_progressBar_1 = new GridBagConstraints();
        gbc_progressBar_1.insets = new Insets(0, 0, 5, 0);
        gbc_progressBar_1.fill = GridBagConstraints.HORIZONTAL;
        gbc_progressBar_1.gridx = 1;
        gbc_progressBar_1.gridy = 1;
        panel.add(progressBarNodesForThisPass, gbc_progressBar_1);
        
        JLabel lblFinishStatus = new JLabel("Finish status");
        GridBagConstraints gbc_lblFinishStatus = new GridBagConstraints();
        gbc_lblFinishStatus.anchor = GridBagConstraints.EAST;
        gbc_lblFinishStatus.insets = new Insets(0, 0, 0, 5);
        gbc_lblFinishStatus.gridx = 0;
        gbc_lblFinishStatus.gridy = 2;
        panel.add(lblFinishStatus, gbc_lblFinishStatus);
        
        lblFinishStatusValue = new JLabel("Finish Status");
        GridBagConstraints gbc_lblFinishStatusValue = new GridBagConstraints();
        gbc_lblFinishStatusValue.gridx = 1;
        gbc_lblFinishStatusValue.gridy = 2;
        panel.add(lblFinishStatusValue, gbc_lblFinishStatusValue);
    }
    
    private void chooseSaveFolder()
    {
        JFileChooser fileChooser = new JFileChooser(".");
        fileChooser.setMultiSelectionEnabled(false);
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int ret = fileChooser.showOpenDialog(this);
        switch (ret)
        {
            case JFileChooser.APPROVE_OPTION:
                saveFile = fileChooser.getSelectedFile();
                txtSavePath.setText(saveFile.getAbsolutePath());
                break;
            
            default:
                break;
        }
    }
    
    private void stopComputation()
    {
        keepComputing = false;
        btnStop.setText("Stopping...");
        mainWindow.getQuadTreeManager().stopNow();
        try
        {
            computationThread.join();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
    
    private void startComputation()
    {
        QuadTreeManager quadTreeManager = mainWindow.getQuadTreeManager();
        if (quadTreeManager == null)
        {
            mainWindow.showNoQuadTreeError();
            return;
        }
        
        System.out.println("1");
        btnStart.setEnabled(false);
        keepComputing = true;
        quadTreeManager.resetStop();
        
        quadTreeManager.setThreads(((Number) spnrThreads.getValue()).intValue());
        quadTreeManager.setUseOpenCL(mainWindow.useOpenCL());
        int passes = cmbxPasses.getItemAt(cmbxPasses.getSelectedIndex()).value;
        int nodesPerPass = cmbxNodesPerPass.getItemAt(cmbxNodesPerPass.getSelectedIndex()).value;
        int saveEvery = ((Number) spnrSaveEveryXPass.getValue()).intValue();
        
        if (rdbtnFullComputation.isSelected())
        {
            passes = Integer.MAX_VALUE;
        }
        else if (rdbtnPasses.isSelected())
        {
            // already set to the correct value
        }
        
        doComputation(quadTreeManager, passes, nodesPerPass, saveEvery);
    }
    
    private void doComputation(final QuadTreeManager quadTreeManager, final int originalPasses, final int nodesPerPass, final int saveEvery)
    {
        progressBarNodesForThisPass.setMaximum(nodesPerPass);
        progressBarPasses.setMaximum(originalPasses);
        
        quadTreeManager.addQuadTreeManagerListener(new QuadTreeManagerListener()
        {
            @Override
            public void computeProgress(final int current, int total)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        progressBarNodesForThisPass.setValue(current);
                        progressBarNodesForThisPass.setString("" + current + "/" + progressBarNodesForThisPass.getMaximum());
                    }
                });
            }
            
            @Override
            public void computationFinished(final boolean remaining)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if (remaining)
                        {
                            lblFinishStatusValue.setText("Nodes remaining");
                        }
                        else
                        {
                            keepComputing = false;
                            lblFinishStatusValue.setText("No more nodes to compute");
                        }
                    }
                });
            }
            
            @Override
            public void threadSleeping(long threadId)
            {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void threadResumed(long threadId)
            {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void threadStarted(long threadId)
            {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void loadingFile(int current, int total)
            {
                // TODO Auto-generated method stub
                
            }
        });
        
        computationThread = new Thread()
        {
            
            @Override
            public void run()
            {
                int localPasses = originalPasses;
                
                while (localPasses-- > 0 && keepComputing)
                {
                    System.out.println("pass");
                    try
                    {
                        quadTreeManager.compute(nodesPerPass);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                        break;
                    }
                    
                    final int tmpPasses = localPasses;
                    SwingUtilities.invokeLater(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            progressBarPasses.setValue(originalPasses - tmpPasses);
                            progressBarPasses.setString("" + (originalPasses - tmpPasses) + "/" + progressBarPasses.getMaximum());
                            
                            if (chckbxUpdateStatisticsAfter.isSelected())
                            {
                                mainWindow.updateStatistics();
                            }
                            
                            if (chckbxSaveEvery.isSelected())
                            {
                                if (tmpPasses % saveEvery == 0)
                                {
                                    String suffix = "";
                                    if (lblAddSuffix.isSelected())
                                    {
                                        suffix = txtSuffixValue.getText();
                                    }
                                    
                                    try
                                    {
                                        quadTreeManager.saveACopy("", suffix);
                                    }
                                    catch (IOException e)
                                    {
                                        ComputationPanel.this.stopComputation();
                                        JOptionPane.showMessageDialog(ComputationPanel.this, "Error while saving the quad tree to a file\n" + e.getMessage(),
                                        "File error", JOptionPane.ERROR_MESSAGE);
                                    }
                                }
                            }
                        }
                    });
                }
                
                System.out.println("Stop");
                btnStart.setEnabled(true);
                btnStop.setEnabled(false);
                btnStop.setText("Stop");
                
                if (keepComputing)
                {
                    try
                    {
                        if (chckbxOverwriteOriginalFile.isSelected())
                        {
                            quadTreeManager.saveToXML(quadTreeManager.getOriginalPath());
                        }
                        else if (saveFile != null && saveFile.toPath() != null)
                        {
                            quadTreeManager.saveToXML(saveFile.toPath());
                        }
                        else
                        {
                            JOptionPane.showMessageDialog(ComputationPanel.this, "Can't save the QuadTree to a file: no location specified",
                            "Can't save the QuadTree to a file", JOptionPane.WARNING_MESSAGE);
                        }
                    }
                    catch (IOException e)
                    {
                        JOptionPane.showMessageDialog(ComputationPanel.this, "Error while saving the quad tree to a file\n" + e.getMessage(), "File error",
                        JOptionPane.ERROR_MESSAGE);
                        e.printStackTrace();
                    }
                }
            }
        };
        
        computationThread.start();
        btnStop.setEnabled(true);
    }
}
